#include "MS_Comm.h"
#include <sstream>
#include<ctime>
#define M_CS_Pin 10 //低电平使能
#define S_CS_Pin 13 //低电平使能
#define CLK_Pin 14 //高电平使能
#define Dat_Pin 11

static char * pDataRecved = nullptr; //指向空
MasterSlave_RW * MasterSlave_RW::pMS_RW = nullptr;

MasterSlave_RW::RWStat MasterSlave_RW::RecentRWStat = MasterSlave_RW::RWS_SPACE;
MasterSlave_RW::TankStat MasterSlave_RW::m_tankStat = MasterSlave_RW::TS_Waiting;
float MasterSlave_RW::m_batValue=0.0;
float MasterSlave_RW::m_TurretAngle=0.0;//炮塔旋转角度

void RecvData(void);

static char BCC_CheckOut(const char *pdata, int num)
{
    char CC = 0;
    for (size_t i = 0; i < (size_t)num; i++)
    {
        CC ^= *(pdata+i);
    }
    return CC;
}

static char u8ToHex(const char data)
{
    if (data <= 9)
    {
        return data + 48;//转成ascii的0-9
    }
    else if(data>9 && data<16 )
    {
        return data + 55;//转成ascii的A-F
    }
    else
    return 127;//返回一个错误
}

static char u8Tohex(const char data)
{
    if (data <= 9)
    {
        return data + 48;//转成ascii的0-9
    }
    else if(data>9 && data<16 )
    {
        return data + 87;//转成ascii的a-f
    }
    else
    return 127;//返回一个错误
}

void BCC_ASCII(const char *pdata, int num, char CC[])
{
    char check = BCC_CheckOut(pdata,num);
    CC[0] = u8ToHex(check/16);
    CC[1] = u8ToHex(check%16);
}


void MasterSlave_RW::init(void)//功能初始化
{
    if(wiringPiSetup() == -1)
    {
        LOG(ERROR) << "wiringPiSetup init Failed";
        return;
    }
    
    //初始化IO口
    pinMode(M_CS_Pin,OUTPUT);
    pinMode(S_CS_Pin,INPUT);//平常状态是从cs引脚为高电平状态
    //从cs引脚默认为高电平状态，
    pinMode(CLK_Pin,INPUT);
    pinMode(Dat_Pin,OUTPUT);
    pullUpDnControl(CLK_Pin,PUD_DOWN);//CLK引脚下拉
    pullUpDnControl(Dat_Pin,PUD_DOWN);//CLK引脚下拉

    digitalWrite(M_CS_Pin,HIGH);//平常状态是主cs引脚为高电平状态
    pullUpDnControl(S_CS_Pin,PUD_UP);//从机cs引脚上拉
    if(wiringPiISR(S_CS_Pin,INT_EDGE_FALLING,&RecvData) < 0)//下降沿触发
    {
        LOG(INFO) << "IR init : Unable to setup ISR !";
        LOG(ERROR) << "IR init : Unable to setup ISR !";
    }

    LOG(DEBUG)  << "Spi recvData init ok !";
    pDataRecved = new char[64];   //申请64个字节
}

template <typename FuncData>
std::string MasterSlave_RW::EncodeFuncD(std::string _func, FuncData _funcData)//按协议编码数据
{
    std::ostringstream buffer;
    buffer << "&dat,MS,"<< _func << "," << _funcData << "#";
    char CC[2]; 
    BCC_ASCII((buffer.str().c_str() + 1  ),buffer.str().length()-2,CC);
    buffer << CC[0] << CC[1];
    return buffer.str();
}

std::pair<std::string, int> MasterSlave_RW::DecodeDataF(std::string Data)//按协议接码数据
{
    char CC[2];
    BCC_ASCII((Data.c_str() + 1),Data.length()-4,CC);
    if (CC[1] != *(Data.rbegin()) || CC[0] != *(++Data.rbegin()))
    {
        return std::make_pair(std::string(""), -1);
    }
    else
    {
        // std::cout<<"checked ok!"<<std::endl;
        std::string func;
        size_t idx = 0;
        for (size_t i = 0; i < 2; i++)
        {
            idx = Data.find(',',idx+1);
        }
        if (idx == std::string::npos)
        {
            return std::make_pair(std::string(""), -1);
        }
        else
        {
            func = Data.substr(idx+1,Data.find(',',idx+1)-idx-1);
            // std::cout<<"func = " << func <<std::endl;
            idx = Data.find(',',idx+1);
            int num = 0;
            try {
                //std::cout<<"num = " << num <<std::endl;
                num = std::stoi(Data.substr(idx+1,Data.find('#',idx+1) - idx - 1));
                //std::cout<<"now,num = " << num <<std::endl;
            }
            catch (std::invalid_argument& e) {
                LOG(ERROR) << __func__ << "Invalid argument";
            }
            catch (std::out_of_range& e) {
                LOG(ERROR) << __func__  << "Out of range" ;
            }
            catch (...) {
                LOG(ERROR) << __func__ << "Something else" ;
            }
            
            return std::make_pair(func, num); 
        }
    }
}

void MasterSlave_RW::SendByte(char data)
{
    for (int i = 7; i >= 0; i--)//Master bit first// 高位先发送
    {
        digitalWrite(Dat_Pin, ((data>>i)&0x01));
        delayMicroseconds(2);
        digitalWrite(CLK_Pin, HIGH);
        delayMicroseconds(2);//这个要维持1us
        digitalWrite(CLK_Pin, LOW);
        digitalWrite(Dat_Pin, LOW);
        delayMicroseconds(2);
    }
}


void MasterSlave_RW::SendBytes(const char *pdata, int num)//低字节先发送
{
    //不论主机还是从机，当需要发送时只要检测到对方的CS线为低电平，就等待10ms,如果还没有上拉，则就跳出异常,不在发送
    int errTime = 0;
    while (!digitalRead(S_CS_Pin))
    {
        if (errTime++ >10)
        {
            LOG(ERROR) << "MS_COMM:SendBytes err, conn't send!";
            return;//放弃发送数据，并报错
        }
        delay(1);
    }

    if (MasterSlave_RW::RecentRWStat != MasterSlave_RW::RWS_TX)//如果当前不为接收数据状态
    {
        pinMode(CLK_Pin,OUTPUT);//clk引脚变为输出状态
        pullUpDnControl(CLK_Pin,PUD_DOWN);//CLK引脚下拉
        pullUpDnControl(Dat_Pin,PUD_DOWN);//DAT引脚下拉
        MasterSlave_RW::RecentRWStat = MasterSlave_RW::RWS_TX;
    }

    digitalWrite(M_CS_Pin,LOW);
    delay(1);//1ms等待从机切换状态
    for (size_t i = 0; i < num; i++)
    {
        if (MasterSlave_RW::RecentRWStat != MasterSlave_RW::RWS_TX)//应该保持发送状态
        {
            break;//退出
        }
        SendByte(*(pdata+i));
    }
    digitalWrite(M_CS_Pin,HIGH);//结束传输
}

void MasterSlave_RW::ReadDataFromSpi(void) //在中断中读取数据
{
    auto timeval_Span_s  = [=](time_t * tv_last) ->  unsigned int
    {
        time_t nowtime;
        time(&nowtime);
        return (*tv_last - nowtime);
    };

    if (MasterSlave_RW::RecentRWStat == MasterSlave_RW::RWS_TX)
    {
        MasterSlave_RW::RecentRWStat = MasterSlave_RW::RWS_RX;//接收状态
        pinMode(CLK_Pin,INPUT);//clk引脚立即变为输入状态
        pullUpDnControl(CLK_Pin,PUD_DOWN);//CLK引脚下拉
        pullUpDnControl(Dat_Pin,PUD_DOWN);//DAT引脚下拉
    }
    
    // std::cout << "begin recved!" <<std::endl;
    //打开clk中断
    time_t _time;
    time(&_time);//获取当前时间
    int pos = 0;//当前的位置
    while (!digitalRead(S_CS_Pin))
    {
        for (int i = 7; i >= 0; i--)//接收8个数据
        {
            while (!digitalRead(CLK_Pin) && !digitalRead(S_CS_Pin) && (timeval_Span_s(&_time)<2));//等待clk电平拉高
            if(!digitalRead(S_CS_Pin))
            {
                *(pDataRecved + pos) |= ((digitalRead(Dat_Pin)&0x01)<<i);// 然后采样
            }
            while (digitalRead(CLK_Pin)&&!digitalRead(S_CS_Pin) && (timeval_Span_s(&_time)<2));//等待clk电平拉低
            if(digitalRead(S_CS_Pin)) break;
        }
        // std::cout <<*(pDataRecved + pos)<<std::endl;
        if(!digitalRead(S_CS_Pin)) pos++;
    }
    if (timeval_Span_s(&_time)>=2) return;//直接退出
    std::cout << "recved size = " << pos<<std::endl;
    std::string TheDataRecved(pDataRecved, (std::string::size_type)pos);//此时pos正好是接收了多少个char

    std::cout << "The data recved is : "<< std::hex;
    for(int i = 0; i < pos ; i++)
    {
        std::cout << (int)*(pDataRecved+i) <<" ";
    }
    std::cout << std::endl;
    std::cout << "The data recved is :"<< TheDataRecved <<std::endl;
    // LOG(DEBUG) << "The data recved is :"<< TheDataRecved;//收到的数据
    std::pair<std::string, int> ppp = DecodeDataF(TheDataRecved); //数据拆解
    // std::cout<<"ppp.second = " << num << std::endl;
    // std::cout<<ppp.first<<ppp.second<<std::endl;
    if (ppp.first == "BAT")//数据是BAT
    {
        MasterSlave_RW::m_batValue = (float)ppp.second / 100.0f;
    }
    else if (ppp.first == "TS")
    {
        MasterSlave_RW::m_tankStat = (MasterSlave_RW::TankStat)ppp.second;
    }
    else if (ppp.first == "TR")
    {
        MasterSlave_RW::m_TurretAngle = ppp.second / 10.0f;
    }
    std::cout<<"over!"<<std::endl;
    memset(pDataRecved, 0, 64);            //64个字节全部置0
}

void RecvData(void)
{
    MasterSlave_RW::pMS_RW->ReadDataFromSpi();
}


MasterSlave_RW::TankStat MasterSlave_RW::ReadTankStat(void)
{
    return MasterSlave_RW::m_tankStat;
}


MasterSlave_RW::MasterSlave_RW()
{
}

MasterSlave_RW::~MasterSlave_RW()
{
    if (pDataRecved != nullptr)//清空数据
    {
        delete pDataRecved;
        pDataRecved = nullptr;
    }
}

float MasterSlave_RW::ReadBAT(void)
{
    return MasterSlave_RW::m_batValue;
}


float MasterSlave_RW::ReadTurretAngle(void)
{
    return MasterSlave_RW::m_TurretAngle;
}

void MasterSlave_RW::SendBeHidSignal(void)
{
    std::string data = EncodeFuncD("BH",1);
    SendBytes(data.c_str(),data.length());
}


void MasterSlave_RW::SetLightStat(MasterSlave_RW::LStat stat, bool IsFrontLight)
{
    std::string data;
    if (IsFrontLight)
    {
        data = EncodeFuncD("FL",(int)stat);
    }
    else
    {
        data = EncodeFuncD("BL",(int)stat);
    }
    SendBytes(data.c_str(),data.length());
}

